package com.rex.saas.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rex.saas.bean.*;
import com.rex.saas.bean.request.*;
import com.rex.saas.bean.response.LoginResponse;
import com.rex.saas.constants.Constants;
import com.rex.saas.db.entity.SaasDeviceInfo;
import com.rex.saas.db.entity.SaasSpaceInfo;
import com.rex.saas.db.entity.SaasUserInfo;
import com.rex.saas.db.entity.SaasUserSpaceRelation;
import com.rex.saas.db.mapper.SaasSpaceInfoMapper;
import com.rex.saas.db.mapper.SaasUserInfoMapper;
import com.rex.saas.db.mapper.SaasUserSpaceRelationMapper;
import com.rex.saas.enums.StatusEnum;
import com.rex.saas.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @ClassName UserService
 * @Description:
 * @Author: zhusiyu
 * @CreateDate: 2024/12/18 11:06	//创建时间
 */
@Component
@Slf4j
public class UserService {

    @Autowired
    RexolarApiClient rexolarApiClient;

    @Autowired
    SaasUserInfoMapper saasUserInfoMapper;

    @Autowired
    SaasSpaceInfoMapper saasSpaceInfoMapper;

    @Autowired
    SaasUserSpaceRelationMapper saasUserSpaceRelationMapper;

    @Autowired
    DeviceService deviceService;

    @Autowired
    SpaceService spaceService;


    private static Map<String, String> tenantMap = new HashMap<>();

    public void syncTenantMap(){
        String sysToken = rexolarApiClient.getToken();
        if(StringUtils.isEmpty(sysToken)){
            log.error("获取系统管理员token失败！");
            return;
        }
        List<TenantBasicData> tenantBasicDataList = rexolarApiClient.getTenants(sysToken, null);
        for (int i = 0; i < tenantBasicDataList.size(); i++){
            TenantBasicData tenantBasicData = tenantBasicDataList.get(i);
            tenantMap.put(tenantBasicData.getName(), tenantBasicData.getId());
        }
        if (CollectionUtils.isEmpty(tenantMap)){
            log.error("syncTenantMap tenantMap is empty！");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                log.error("syncTenantMap InterruptedException");
            }
            syncTenantMap();
        }
    }
    /**
     * 登陆
     * @param loginRequest
     * @return
     */
    public BaseResponse login(LoginRequest loginRequest) {
        /*校验用户名和密码*/
        Map tokenMap = rexolarApiClient.authLogin(loginRequest.getUsername(),loginRequest.getPassword());
        if (tokenMap == null || tokenMap.size() == 0){
            return BaseResponse.error(ResultCode.LOGIN_ERROR);
        }
        /*解析token*/
        String tenantToken = (String) tokenMap.get("token");
        String refreshToken = (String) tokenMap.get("refreshToken");
        Map payload = JwtUtils.getPayload(tenantToken);

        /*生成返回体*/
        LoginResponse loginResponse = new LoginResponse();
        loginResponse.setToken(tenantToken);
        loginResponse.setRefreshToken(refreshToken);
        loginResponse.setUserId(payload.get("userId").toString());
        loginResponse.setAuthority(payload.get("scopes").toString());
        loginResponse.setExt(Long.parseLong(payload.get("exp").toString()));
        loginResponse.setUsername(payload.get("sub").toString());
        loginResponse.setTenantId(payload.get("tenantId").toString());

        return BaseResponse.ok(loginResponse);
    }

    /**
     * 登陆
     * @param loginRequest
     * @return
     */
    public BaseResponse ctLogin(LoginRequest loginRequest) {
        SaasUserInfo saasUserInfo = getUserByUsername(loginRequest.getUsername());
        if (saasUserInfo == null) {
            log.error("User is null, email:{}", loginRequest.getUsername());
            return BaseResponse.error(ResultCode.PARAM_ERROR.getStatus(), "email is wrong！");
        }
        if(!loginRequest.getPassword().equals(saasUserInfo.getPassword())){
            log.error("ctLogin password is wrong, user:{}", saasUserInfo);
            return BaseResponse.error(ResultCode.LOGIN_ERROR.getStatus(), "password is wrong!");
        }
        String tenantId = saasUserInfo.getTenantId();
        if(StringUtils.isEmpty(tenantId)){
            log.error("ctLogin ctTenantId is null, user:{}", saasUserInfo);
            return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "租户ID为空！");
        }
        String token = rexolarApiClient.getTenantToken(tenantId);
        if(StringUtils.isEmpty(token)){
            log.error("ctLogin getToken error");
            return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "获取租户token失败！");
        }
        Map tokenMap = rexolarApiClient.getUserToken(saasUserInfo.getCoreId(), token);
        if (tokenMap == null || tokenMap.size() == 0){
            return BaseResponse.error(ResultCode.LOGIN_ERROR);
        }

        /*解析token*/
        String tenantToken = (String) tokenMap.get("token");
        String refreshToken = (String) tokenMap.get("refreshToken");
        Map payload = JwtUtils.getPayload(tenantToken);

        /*生成返回体*/
        LoginResponse loginResponse = new LoginResponse();
        loginResponse.setToken(tenantToken);
        loginResponse.setRefreshToken(refreshToken);
        loginResponse.setUserId(payload.get("userId").toString());
        loginResponse.setAuthority(payload.get("scopes").toString());
        loginResponse.setExt(Long.parseLong(payload.get("exp").toString()));
        loginResponse.setUsername(payload.get("sub").toString());

        return BaseResponse.ok(loginResponse);
    }

    /**
     * 登陆
     * @param token
     * @return
     */
    public BaseResponse logout(String token) {
        Map tokenMap = rexolarApiClient.getUserToken(JwtUtils.getUserId(token), rexolarApiClient.getTenantToken(JwtUtils.getTenantId(token)));
        if(CollectionUtils.isEmpty(tokenMap)){
            log.error("logout error, user:{}", token);
            return BaseResponse.error(ResultCode.LOGOUT_ERROR);
        }
        return BaseResponse.ok();
    }
    @Transactional
    public BaseResponse ctRegister(RegisterRequest registerRequest) {
        LambdaQueryWrapper<SaasUserInfo> allQueryWrapper = new LambdaQueryWrapper<>();
        allQueryWrapper.eq(SaasUserInfo::getUsername, registerRequest.getEmail());
        allQueryWrapper.eq(SaasUserInfo::getStatus, StatusEnum.ENABLE.getCode());
        allQueryWrapper.eq(SaasUserInfo::getType, Constants.SAAS);
        List<SaasUserInfo> list = saasUserInfoMapper.selectList(allQueryWrapper);
        if (!CollectionUtils.isEmpty(list)){
            log.error("register getTenantId email exist!, user:{}", list.get(0));
            return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "该邮箱已注册！");
        }

        String token = rexolarApiClient.getTenantToken(tenantMap.get("currentTransformer"));
        if(StringUtils.isEmpty(token)){
            log.error("register getTenantToken error");
            return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "获取getTenantToken失败！");
        }
        SaasUserInfo saasUserInfo = new SaasUserInfo();
        String customerId = null;
        List<Map> customIds = rexolarApiClient.getCustomersByEmail(token, registerRequest.getEmail());
        if(CollectionUtils.isEmpty(customIds)){
            customerId = rexolarApiClient.dynamicCreateCustomer(registerRequest.getEmail(), tenantMap.get("currentTransformer"),token);
            if(StringUtils.isEmpty(customerId)){
                return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "创建客户失败！");
            }
            saasUserInfo.setTenantId(tenantMap.get("currentTransformer"));
        }else{
            customerId = (String) customIds.get(0).get("id");
            if(customIds.size()>1){
                log.warn("register getCustomersByEmail error, customIds size:{}", customIds);
            }
        }
        String userId = null;
        List<UserBasicData> users = rexolarApiClient.getCustomerUsers(customerId, token);
        if (!CollectionUtils.isEmpty(users)){
            for (UserBasicData userBasicData : users) {
                if (userBasicData.getEmail().equals(registerRequest.getEmail())){
                    userId = userBasicData.getId();
                }
            }
        }else {
            userId = rexolarApiClient.createCustomUser(registerRequest.getEmail(), tenantMap.get("currentTransformer"), customerId, token);
            if(StringUtils.isEmpty(userId)){
                return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "创建账号失败！");
            }
        }

        saasUserInfo = new SaasUserInfo();
        saasUserInfo.setUsername(registerRequest.getEmail());
        saasUserInfo.setPassword(registerRequest.getPassword());
        saasUserInfo.setMail(registerRequest.getEmail());
        saasUserInfo.setMailPassword(registerRequest.getPassword());
        saasUserInfo.setTenantId(tenantMap.get("currentTransformer"));
        saasUserInfo.setCoreId(userId);
        saasUserInfo.setCustomerId(customerId);
        saasUserInfo.setStatus(StatusEnum.ENABLE.getCode());
        saasUserInfo.setType(Constants.SAAS);
        if(saasUserInfoMapper.insert(saasUserInfo)!=1){
            log.error("register insert saasUserInfo error, saasUserInfo:{}", saasUserInfo);
            return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "创建用户失败！");
        }
        return BaseResponse.ok(userId);
    }

    public boolean updatePassword(SaasUserInfo saasUserInfo, String newPassword) {
        saasUserInfo.setPassword(newPassword);
        saasUserInfo.setMailPassword(newPassword);
        return  saasUserInfoMapper.updateById(saasUserInfo)==1;
    }

    @Transactional
    public BaseResponse logoff(LogoffRequest logoffRequest, String token) {
        SaasUserInfo saasUserInfo = getUserByUsername(logoffRequest.getUsername());
        if (saasUserInfo == null){
            log.error("logoff error, user is null, user:{}", logoffRequest);
            return BaseResponse.error(ResultCode.NOT_EXIST_ERROR);
        }
        if (saasUserInfo.getStatus().intValue() == StatusEnum.DELETED.getCode()){
            log.error("logoff error, user is deleted, user:{}", saasUserInfo);
            return BaseResponse.error(ResultCode.NOT_EXIST_ERROR);
        }
        if(!logoffRequest.getPassword().equals(saasUserInfo.getPassword())){
            log.error("logoff password is wrong, user:{}", saasUserInfo);
            return BaseResponse.error(ResultCode.LOGIN_ERROR.getStatus(), "password is wrong!");
        }

        List<SaasDeviceInfo> devices = deviceService.getDeviceByUser(JwtUtils.getCustomerId(token));
        String tenantToken = rexolarApiClient.getTenantToken(saasUserInfo.getTenantId());
        for (SaasDeviceInfo device : devices) {
            if(!deviceService.networkLeave(device, tenantToken)){
                log.error("logoff networkLeave error, device:{}", device);
                return BaseResponse.error("设备离网失败", ResultCode.SYSTEM_ERROR);
            }

            boolean result = deviceService.deleteCustomerDevice(device, tenantToken);
            if (!result){
                log.error("logoff delete device error, device:{}", device);
                return BaseResponse.error(ResultCode.SYSTEM_ERROR);
            }
        }

        spaceService.deleteSpaceByUser(token);
        boolean result = rexolarApiClient.deleteCustomer(saasUserInfo.getCustomerId(), tenantToken);
        if (!result){
            log.error("logoff deleteCustomer error, user:{}", saasUserInfo);
            return BaseResponse.error(ResultCode.SYSTEM_ERROR);
        }
        return BaseResponse.ok(saasUserInfoMapper.deleteById(saasUserInfo.getId())==1);
    }

    public SaasUserInfo getUserByUsername(String username) {
        LambdaQueryWrapper<SaasUserInfo> allQueryWrapper = new LambdaQueryWrapper<>();
        allQueryWrapper.eq(SaasUserInfo::getUsername, username);
        allQueryWrapper.eq(SaasUserInfo::getStatus, StatusEnum.ENABLE.getCode());
        List<SaasUserInfo> list = saasUserInfoMapper.selectList(allQueryWrapper);
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        return list.get(0);
    }

    public BaseResponse add(UserAddRequest userAddRequest, String token) {
        LambdaQueryWrapper<SaasUserInfo> allQueryWrapper = new LambdaQueryWrapper<>();
        allQueryWrapper.eq(SaasUserInfo::getUsername, userAddRequest.getEmail());
        allQueryWrapper.eq(SaasUserInfo::getStatus, StatusEnum.ENABLE.getCode());
        allQueryWrapper.eq(SaasUserInfo::getType, Constants.SAAS);
        List<SaasUserInfo> list = saasUserInfoMapper.selectList(allQueryWrapper);
        if (!CollectionUtils.isEmpty(list)){
            log.error("add getTenantId email exist!, user:{}", list.get(0));
            return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "该邮箱已注册！");
        }

        String tenantId = JwtUtils.getTenantId(token);
        SaasUserInfo saasUserInfo = new SaasUserInfo();
        String customerId = null;
        List<Map> customIds = rexolarApiClient.getCustomersByEmail(token, userAddRequest.getEmail());
        if(CollectionUtils.isEmpty(customIds)){
            customerId = rexolarApiClient.dynamicCreateCustomer(userAddRequest.getEmail(), tenantId,token);
            if(StringUtils.isEmpty(customerId)){
                return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "创建客户失败！");
            }
            saasUserInfo.setTenantId(JwtUtils.getTenantId( token));
        }else{
            customerId = (String) customIds.get(0).get("id");
            if(customIds.size()>1){
                log.warn("add getCustomersByEmail error, customIds size:{}", customIds);
            }
        }
        String userId = null;
        List<UserBasicData> users = rexolarApiClient.getCustomerUsers(customerId, token);
        if (!CollectionUtils.isEmpty(users)){
            for (UserBasicData userBasicData : users) {
                if (userBasicData.getEmail().equals(userAddRequest.getEmail())){
                    userId = userBasicData.getId();
                }
            }
        }else {
            userId = rexolarApiClient.createCustomUser(userAddRequest.getEmail(), tenantId, customerId, token);
            if(StringUtils.isEmpty(userId)){
                return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "创建账号失败！");
            }
        }

        saasUserInfo = new SaasUserInfo();
        saasUserInfo.setUsername(userAddRequest.getEmail());
        saasUserInfo.setPassword(userAddRequest.getPassword());
        saasUserInfo.setMail(userAddRequest.getEmail());
        saasUserInfo.setMailPassword(userAddRequest.getPassword());
        saasUserInfo.setTenantId(tenantId);
        saasUserInfo.setCoreId(userId);
        saasUserInfo.setCustomerId(customerId);
        saasUserInfo.setStatus(StatusEnum.ENABLE.getCode());
        saasUserInfo.setType(Constants.SAAS);
        if(saasUserInfoMapper.insert(saasUserInfo)!=1){
            log.error("add insert saasUserInfo error, saasUserInfo:{}", saasUserInfo);
            return BaseResponse.error(ResultCode.SYSTEM_ERROR.getStatus(), "创建用户失败！");
        }
        return BaseResponse.ok(saasUserInfo.getId());
    }

    public List<UserInfo> list(String tenantId) {
        LambdaQueryWrapper<SaasUserInfo> allQueryWrapper = new LambdaQueryWrapper<>();
        allQueryWrapper.eq(SaasUserInfo::getTenantId, tenantId);
        allQueryWrapper.eq(SaasUserInfo::getStatus, StatusEnum.ENABLE.getCode());
        allQueryWrapper.eq(SaasUserInfo::getType, Constants.SAAS);
        List<SaasUserInfo> list = saasUserInfoMapper.selectList(allQueryWrapper);
        List <UserInfo> userInfoList = new ArrayList<>();
        for (SaasUserInfo saasUserInfo : list) {
            UserInfo userInfo = new UserInfo();
            BeanUtils.copyProperties(saasUserInfo, userInfo);
            userInfo.setCreatedTime(saasUserInfo.getCreateTime().getTime());
            userInfoList.add(userInfo);
        }
        return userInfoList;
    }

    public SaasUserInfo getUserById(Long id) {
        return saasUserInfoMapper.selectById(id);
    }

    public List<SpaceInfo> getUserSpaces(Long id) {
        List<SpaceInfo> spaceInfoList = new ArrayList<>();
        List<SaasUserSpaceRelation> list = saasUserSpaceRelationMapper.selectList(new LambdaQueryWrapper<SaasUserSpaceRelation>().eq(SaasUserSpaceRelation::getUserId, id));
        for (SaasUserSpaceRelation saasUserSpaceRelation : list){
            SpaceInfo spaceInfo = new SpaceInfo();
            SaasSpaceInfo saasSpaceInfo = saasSpaceInfoMapper.selectById(saasUserSpaceRelation.getSpaceId());
            if (saasSpaceInfo==null){
                log.error("getUserSpaces saasSpaceInfo is null, spaceId:{}", saasUserSpaceRelation.getSpaceId());
                continue;
            }
            BeanUtils.copyProperties(saasSpaceInfo, spaceInfo);
            spaceInfoList.add(spaceInfo);
        }
        return spaceInfoList;
    }

    public Boolean space(UserSpaceRequest spaceRequest) {
        List<SaasUserSpaceRelation> list = saasUserSpaceRelationMapper.selectList(new LambdaQueryWrapper<SaasUserSpaceRelation>()
                .eq(SaasUserSpaceRelation::getUserId, spaceRequest.getUserId()).eq(SaasUserSpaceRelation::getSpaceId, spaceRequest.getSpaceId()));
        if (!CollectionUtils.isEmpty(list)){
            return true;
        }
        SaasUserSpaceRelation saasUserSpaceRelation = new SaasUserSpaceRelation();
        saasUserSpaceRelation.setUserId(spaceRequest.getUserId());
        saasUserSpaceRelation.setSpaceId(spaceRequest.getSpaceId());
        saasUserSpaceRelation.setGmtCreated(new Date());
        saasUserSpaceRelation.setGmtModified(new Date());
        return saasUserSpaceRelationMapper.insert(saasUserSpaceRelation) == 1;
    }

    public Boolean stop(Long id) {
        SaasUserInfo saasUserInfo = saasUserInfoMapper.selectById(id);
        if (saasUserInfo==null){
            log.error("stop saasUserInfo is null, id:{}", id);
            return false;
        }
        saasUserInfo.setStatus(StatusEnum.DISABLE.getCode());
        saasUserInfo.setUpdateTime(new Date());
        return saasUserInfoMapper.updateById(saasUserInfo) == 1;
    }
}
